/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.web.editors.project;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.cmd.identity.*;
import cn.easyplatform.studio.context.Contexts;
import cn.easyplatform.studio.utils.SecurityUtils;
import cn.easyplatform.studio.utils.WebUtils;
import cn.easyplatform.studio.vos.OrgVo;
import cn.easyplatform.studio.vos.RoleVo;
import cn.easyplatform.studio.vos.UserVo;
import cn.easyplatform.studio.web.editors.AbstractPanelEditor;
import cn.easyplatform.studio.web.layout.WorkbenchController;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.*;
import org.zkoss.zul.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public class UserEditor extends AbstractPanelEditor {

    private Listbox userGrid;

    private Textbox key;

    private Textbox name;

    private Textbox password;

    private Combobox type;

    private Datebox validDate;

    private Intbox validDays;

    private Combobox state;

    private Listbox sourceRoles;

    private Listbox targetRoles;

    private Listbox sourceOrgs;

    private Listbox targetOrgs;

    private Textbox searchTextbox;

    private Textbox searchRoleTextbox;

    private Textbox searchOrgTextbox;

    private List<RoleVo> allRoles;

    private List<OrgVo> allOrgs;

    private UserVo selectedUser;

    public UserEditor(WorkbenchController workbench, String id) {
        super(workbench, id);
    }

    @Override
    public void create(Object... args) {
        Idspace is = createPanel(Labels.getLabel("menu.user"), "~./images/user.png", "~./include/editor/project/user.zul");
        for (Component comp : is.getFellows()) {
            if (comp.getId().equals("projectUser_listbox_userGrid")) {
                userGrid = (Listbox) comp;
                userGrid.getPaginal().setDetailed(false);
            } else if (comp.getId().equals("projectUser_textbox_id"))
                key = (Textbox) comp;
            else if (comp.getId().equals("projectUser_textbox_name"))
                name = (Textbox) comp;
            else if (comp.getId().equals("projectUser_textbox_password"))
                password = (Textbox) comp;
            else if (comp.getId().equals("projectUser_combobox_type")) {
                type = (Combobox) comp;
                type.setSelectedIndex(1);
                comp.addEventListener(Events.ON_OPEN, this);
            } else if (comp.getId().equals("projectUser_datebox_validDate")) {
                validDate = (Datebox) comp;
            } else if (comp.getId().equals("projectUser_intbox_validDays")) {
                validDays = (Intbox) comp;
            } else if (comp.getId().equals("projectUser_combobox_state")) {
                state = (Combobox) comp;
                state.setSelectedIndex(0);
            } else if (comp.getId().equals("projectUser_listbox_sourceRoles")) {
                sourceRoles = (Listbox) comp;
            } else if (comp.getId().equals("projectUser_listbox_targetRoles")) {
                targetRoles = (Listbox) comp;
                comp.addEventListener(Events.ON_DROP, this);
            } else if (comp.getId().equals("projectUser_listbox_sourceOrgs")) {
                sourceOrgs = (Listbox) comp;
            } else if (comp.getId().equals("projectUser_listbox_targetOrgs")) {
                targetOrgs = (Listbox) comp;
                comp.addEventListener(Events.ON_DROP, this);
            } else if (comp instanceof Button) {
                String AuthorizedKey = null;
                if (comp.getId().equals("projectUser_button_userAdd"))
                    AuthorizedKey = "userAdd";
                else if (comp.getId().equals("projectUser_button_userDelete"))
                    AuthorizedKey = "userDelete";
                else if (comp.getId().equals("projectUser_button_userEdit"))
                    AuthorizedKey = "userEdit";
                else if (comp.getId().equals("projectUser_button_userReset"))
                    AuthorizedKey = "userReset";
                boolean isAuthorized = Contexts.getUser().isAuthorized(AuthorizedKey);
                if (isAuthorized)
                    comp.addEventListener(Events.ON_CLICK, this);
                else
                    ((Button) comp).setDisabled(true);
            } else if (comp instanceof Image) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("projectUser_textbox_search")) {
                searchTextbox = (Textbox) comp;
                searchTextbox.addEventListener(Events.ON_OK, this);
            } else if (comp.getId().equals("projectUser_textbox_searchRole")) {
                searchRoleTextbox = (Textbox) comp;
                searchRoleTextbox.addEventListener(Events.ON_OK, this);
            } else if (comp.getId().equals("projectOrg_textbox_searchRole")) {
                searchOrgTextbox = (Textbox) comp;
                searchOrgTextbox.addEventListener(Events.ON_OK, this);
            }
        }
        redraw();
        selectedUser = new UserVo();
        selectedUser.setCode('C');
        setValue();
    }

    private void redraw() {
        List<UserVo> users = StudioApp.execute(new GetUsersCmd());
        redrawUsers(users);
        allRoles = StudioApp.execute(new GetRolesCmd());
        redrawRoleVos(allRoles);
        allOrgs = StudioApp.execute(new GetOrgsCmd());
        redrawOrgVos(allOrgs);
    }

    private void redrawUsers(List<UserVo> users) {
        userGrid.getItems().clear();
        for (UserVo user : users) {
            Listitem row = new Listitem();
            row.setValue(user);
            row.appendChild(new Listcell(user.getId()));
            row.appendChild(new Listcell(user.getName()));
            row.addEventListener(Events.ON_CLICK, this);
            userGrid.appendChild(row);
        }
    }

    private void redrawRoleVos(List<RoleVo> roleVoList) {
        sourceRoles.getItems().clear();
        for (RoleVo role : roleVoList) {
            Listitem row = new Listitem();
            row.setValue(role);
            row.appendChild(new Listcell(role.getId()));
            String typeString;
            /*if (Strings.isBlank(role.getType()) == false && role.getType().equals("mil")) {
                typeString = Labels.getLabel("device.mobile");
            } else
                typeString = Labels.getLabel("device.desktop");
            row.appendChild(new Listcell(typeString));*/
            row.appendChild(new Listcell(role.getName()));
            row.appendChild(new Listcell(role.getDesp()));
            row.setDraggable("role");
            sourceRoles.appendChild(row);
        }
    }

    private void redrawOrgVos(List<OrgVo> orgVos) {
        sourceOrgs.getItems().clear();
        for (OrgVo org : orgVos) {
            Listitem row = new Listitem();
            row.setValue(org);
            row.appendChild(new Listcell(org.getId()));
            row.appendChild(new Listcell(org.getName()));
            row.setDraggable("org");
            sourceOrgs.appendChild(row);
        }
    }

    private void refreshRoles(List<String> selectedItems) {
        targetRoles.getItems().clear();
        // 目标
        for (String id : selectedItems) {
            for (RoleVo vo : allRoles) {
                if (id.equals(vo.getId())) {
                    targetRoles.appendChild(createRole(vo));
                    break;
                }
            }
        }
    }

    private void refreshOrgs(List<String> selectedItems) {
        targetOrgs.getItems().clear();
        // 目标
        for (String id : selectedItems) {
            for (OrgVo vo : allOrgs) {
                if (id.equals(vo.getId())) {
                    targetOrgs.appendChild(createOrg(vo));
                    break;
                }
            }
        }
    }

    private Listitem createRole(RoleVo vo) {
        Listitem li = new Listitem();
        li.setValue(vo);
        li.appendChild(new Listcell(vo.getId()));
        String typeString;
        /*if (Strings.isBlank(vo.getType()) == false && vo.getType().equals("mil")) {
            typeString = Labels.getLabel("device.mobile");
        } else
            typeString = Labels.getLabel("device.desktop");
        li.appendChild(new Listcell(typeString));*/
        li.appendChild(new Listcell(vo.getName()));
        li.appendChild(new Listcell(vo.getDesp()));
        li.setDraggable("role");
        li.setDroppable("role");
        li.addEventListener(Events.ON_DROP, this);
        return li;
    }

    private Listitem createOrg(OrgVo vo) {
        Listitem li = new Listitem();
        li.setValue(vo);
        li.appendChild(new Listcell(vo.getId()));
        li.appendChild(new Listcell(vo.getName()));
        li.setDroppable("org");
        li.addEventListener(Events.ON_DROP, this);
        return li;
    }

    private void setValue() {
        key.setValue(selectedUser.getId());
        name.setValue(selectedUser.getName());
        password.setValue(selectedUser.getPassword());
        type.setSelectedIndex(selectedUser.getType() + 1);
        validDate.setValue(selectedUser.getValidDate());
        validDays.setValue(selectedUser.getValidDays());
        state.setSelectedIndex(selectedUser.getState());
        if (selectedUser.getCode() != 'C') {
            refreshRoles(StudioApp.execute(new GetUserRoleCmd(selectedUser
                    .getId())));
            refreshOrgs(StudioApp.execute(new GetUserOrgCmd(selectedUser
                    .getId())));
        } else {
            targetRoles.getItems().clear();
        }
    }

    @Override
    public void dispatch(Event event) {
        if (event.getName().equals(Events.ON_DROP)) {
            if (selectedUser == null) {
                WebUtils.showError(Labels.getLabel("editor.select",
                        new String[]{Labels.getLabel("menu.studio.user")}));
                return;
            }
            DropEvent de = (DropEvent) event;
            Listitem source = (Listitem) de.getDragged();
            if (source.getListbox() == targetOrgs) {// 都是targetRoles
                if (de.getTarget() instanceof Listbox) {
                    de.getDragged().detach();
                    targetOrgs.appendChild(de.getDragged());
                } else {
                    int pos = ((Listitem) de.getTarget()).getIndex();
                    Listitem item = (Listitem) de.getDragged();
                    item.detach();
                    targetOrgs.getItems().add(pos, item);
                }
            } else if (source.getListbox() == targetRoles) {// 都是targetRoles
                if (de.getTarget() instanceof Listbox) {
                    de.getDragged().detach();
                    targetRoles.appendChild(de.getDragged());
                } else {
                    int pos = ((Listitem) de.getTarget()).getIndex();
                    Listitem item = (Listitem) de.getDragged();
                    item.detach();
                    targetRoles.getItems().add(pos, item);
                }
            } else {
                Listitem li = (Listitem) de.getDragged();
                if (li.getListbox() == sourceRoles) {
                    RoleVo vo = li.getValue();
                    for (Listitem item : targetRoles.getItems()) {
                        RoleVo mv = item.getValue();
                        if (mv.getId().equals(vo.getId())) {
                            WebUtils.showError(Labels
                                    .getLabel("editor.role.exists"));
                            return;
                        }
                    }
                    if (de.getTarget() instanceof Listbox) {// 加到后面
                        targetRoles.appendChild(createRole(vo));
                    } else {// 加到前面
                        int pos = ((Listitem) de.getTarget()).getIndex();
                        targetRoles.getItems().add(pos, createRole(vo));
                    }
                } else {
                    OrgVo vo = li.getValue();
                    for (Listitem item : targetOrgs.getItems()) {
                        OrgVo mv = item.getValue();
                        if (mv.getId().equals(vo.getId())) {
                            WebUtils.showError(Labels
                                    .getLabel("editor.org.exists"));
                            return;
                        }
                    }
                    if (de.getTarget() instanceof Listbox) {// 加到后面
                        targetOrgs.appendChild(createOrg(vo));
                    } else {// 加到前面
                        int pos = ((Listitem) de.getTarget()).getIndex();
                        targetOrgs.getItems().add(pos, createOrg(vo));
                    }
                }
            }
        } else if (event.getTarget() instanceof Button) {
            if (event.getTarget().getId().equals("projectUser_button_userReset")) {
                if (selectedUser == null || selectedUser.getCode() == 'C') {
                    WebUtils.showError(Labels.getLabel("editor.select",
                            new String[]{Labels.getLabel("menu.studio.user")}));
                    return;
                }
                WebUtils.showConfirm(Labels.getLabel("editor.user.password.reset"), new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event) throws Exception {
                        if (event.getName().equals(Events.ON_OK)) {
                            String password = StudioApp.execute(event.getTarget(),
                                    new PasswordResetCmd(selectedUser.getId()));
                            WebUtils.showInfo(Labels.getLabel(
                                    "editor.user.password.reset.title", new String[]{
                                            selectedUser.getId(), password}));
                        }
                    }
                });
            } else if (event.getTarget().getId().equals("projectUser_button_userAdd")) {
                selectedUser = new UserVo();
                selectedUser.setCode('C');
                key.setReadonly(false);
                password.setReadonly(false);
                setValue();
            } else if (event.getTarget().getId().equals("projectUser_button_userDelete")) {
                if (selectedUser == null || selectedUser.getCode() == 'C') {
                    WebUtils.showError(Labels.getLabel("editor.select",
                            new String[]{Labels.getLabel("menu.studio.user")}));
                    return;
                }
                WebUtils.showConfirm(Labels.getLabel("button.delete"), this);
            } else if (event.getTarget().getId().equals("projectUser_button_userEdit")) {//save
                if (selectedUser == null) {
                    WebUtils.showError(Labels.getLabel("editor.select",
                            new String[]{Labels.getLabel("menu.studio.user")}));
                    return;
                }
                if (Strings.isBlank(key.getValue())) {
                    WebUtils.notEmpty("ID");
                    return;
                }
                if (Strings.isBlank(name.getValue())) {
                    WebUtils.notEmpty(Labels.getLabel("entity.name"));
                    return;
                }
                if (Strings.isBlank(password.getValue())) {
                    WebUtils.notEmpty(Labels.getLabel("user.password"));
                    return;
                }
                selectedUser.setId(key.getValue());
                if (selectedUser.getCode() == 'C') {
                    selectedUser.setPassword(SecurityUtils
                            .encodeBizPassword(password.getValue()));
                    password.setValue(selectedUser.getPassword());
                }
                selectedUser.setName(name.getValue());
                selectedUser.setType(type.getSelectedIndex() - 1);
                selectedUser.setValidDate(validDate.getValue());
                selectedUser.setValidDays(validDays.getValue());
                selectedUser.setState(state.getSelectedIndex());
                List<String> roles = new ArrayList<String>();
                for (Listitem row : targetRoles.getItems()) {
                    RoleVo vo = row.getValue();
                    if (!roles.contains(vo.getId()))
                        roles.add(vo.getId());
                }
                selectedUser.setRoles(roles);
                List<String> orgs = new ArrayList<String>();
                for (Listitem row : targetOrgs.getItems()) {
                    OrgVo vo = row.getValue();
                    if (!orgs.contains(vo.getId()))
                        orgs.add(vo.getId());
                }
                selectedUser.setOrgs(orgs);
                if (StudioApp.execute(event.getTarget(), new UpdateUserCmd(
                        selectedUser))) {
                    if (selectedUser.getCode() == 'C') {
                        Listitem row = new Listitem();
                        row.setValue(selectedUser);
                        row.appendChild(new Listcell(selectedUser.getId()));
                        row.appendChild(new Listcell(selectedUser.getName()));
                        row.addEventListener(Events.ON_CLICK, this);
                        userGrid.appendChild(row);
                        row.setSelected(true);
                    } else {
                        Listitem row = getSelectedRow();
                        List<Listcell> labels = row.getChildren();
                        labels.get(0).setLabel(selectedUser.getId());
                        labels.get(1).setLabel(selectedUser.getName());
                    }
                    selectedUser.setCode('U');
                    password.setReadonly(true);
                    WebUtils.showSuccess(Labels.getLabel("button.save")
                            + Labels.getLabel("menu.studio.user")
                            + selectedUser.getId());
                }
            }
        } else if (event.getTarget() instanceof Image) {
            if (selectedUser == null) {
                WebUtils.showError(Labels.getLabel("editor.select",
                        new String[]{Labels.getLabel("menu.studio.user")}));
                return;
            }
            if (event.getTarget().getId().equals("projectUser_image_role_chooseAllBtn")) {
                List<Listitem> items = sourceRoles.getItems();
                for (Listitem ti : items) {
                    RoleVo vo = ti.getValue();
                    targetRoles.appendChild(createRole(vo));
                }
            } else if (event.getTarget().getId().equals("projectUser_image_role_chooseBtn")) {
                if (sourceRoles.getSelectedCount() > 0) {
                    for (Listitem ti : sourceRoles.getSelectedItems()) {
                        RoleVo vo = ti.getValue();
                        targetRoles.appendChild(createRole(vo));
                    }
                }
            } else if (event.getTarget().getId().equals("projectUser_image_role_removeBtn")) {
                if (targetRoles.getSelectedCount() > 0) {
                    List<Component> cs = new ArrayList<Component>();
                    for (Listitem ti : targetRoles.getSelectedItems())
                        cs.add(ti);
                    for (Component c : cs)
                        c.detach();
                }
            } else if (event.getTarget().getId().equals("projectUser_image_role_removeAllBtn")) {
                targetRoles.getItems().clear();
            } else if (event.getTarget().getId().equals("projectUser_image_org_chooseAllBtn")) {
                List<Listitem> items = sourceOrgs.getItems();
                for (Listitem ti : items) {
                    OrgVo vo = ti.getValue();
                    targetOrgs.appendChild(createOrg(vo));
                }
            } else if (event.getTarget().getId().equals("projectUser_image_org_chooseBtn")) {
                if (sourceOrgs.getSelectedCount() > 0) {
                    for (Listitem ti : sourceOrgs.getSelectedItems()) {
                        OrgVo vo = ti.getValue();
                        targetOrgs.appendChild(createOrg(vo));
                    }
                }
            } else if (event.getTarget().getId().equals("projectUser_image_org_removeBtn")) {
                if (targetOrgs.getSelectedCount() > 0) {
                    List<Component> cs = new ArrayList<Component>();
                    for (Listitem ti : targetOrgs.getSelectedItems())
                        cs.add(ti);
                    for (Component c : cs)
                        c.detach();
                }
            } else if (event.getTarget().getId().equals("projectUser_image_org_removeAllBtn")) {
                targetOrgs.getItems().clear();
            }
        }  else if (event.getTarget().equals(searchTextbox)) {
            if (event instanceof OpenEvent) {
                OpenEvent evt = (OpenEvent) event;
                String val = (String) evt.getValue();
                ((Textbox) event.getTarget()).setValue(val);
            }
            search();
        } else if (event.getTarget().equals(searchRoleTextbox)) {
            if (event instanceof OpenEvent) {
                OpenEvent evt = (OpenEvent) event;
                String val = (String) evt.getValue();
                ((Textbox) event.getTarget()).setValue(val);
            }
            searchRole();
        } else if (event.getTarget().equals(searchOrgTextbox)) {
            if (event instanceof OpenEvent) {
                OpenEvent evt = (OpenEvent) event;
                String val = (String) evt.getValue();
                ((Textbox) event.getTarget()).setValue(val);
            }
            searchOrg();
        } else if (event.getName().equals(Events.ON_OK)) {
            selectedUser.setCode('D');
            if (StudioApp.execute(new UpdateUserCmd(selectedUser))) {
                getSelectedRow().detach();
                selectedUser = new UserVo();
                selectedUser.setCode('C');
                key.setReadonly(false);
                password.setReadonly(false);
                setValue();
            }
        } else if (event.getTarget() instanceof Listitem) {
            Listitem row = (Listitem) event.getTarget();
            selectedUser = row.getValue();
            selectedUser.setCode('U');
            key.setReadonly(true);
            password.setReadonly(true);
            setValue();
        }
    }

    private Listitem getSelectedRow() {
        if (selectedUser == null || selectedUser.getCode() == 'C')
            return null;
        return userGrid.getSelectedItem();
    }

    private void search() {
        List<UserVo> users = StudioApp.execute(new GetUsersCmd());
        List<UserVo> searchVos = new ArrayList<>();
        String searchString = searchTextbox.getValue().trim();
        if (Strings.isBlank(searchString))
            redrawUsers(users);
        else {
            for (UserVo userVo : users) {
                if (userVo.getId().contains(searchString) || userVo.getName().contains(searchString)) {
                    searchVos.add(userVo);
                    continue;
                }
            }
            redrawUsers(searchVos);
        }
    }

    private void searchRole() {
        List<RoleVo> roles = StudioApp.execute(new GetRolesCmd());
        String searchString = searchRoleTextbox.getValue().trim();
        //点击全部，搜索内容为空
        if (Strings.isBlank(searchString))
            redrawRoleVos(roles);
        else {
            List<RoleVo> searchRoles = new ArrayList<>();
            for (RoleVo roleVo: roles) {
                if (Strings.isBlank(searchString)) {
                    searchRoles.add(roleVo);
                    continue;
                } else if (roleVo.getId().contains(searchString)) {
                    searchRoles.add(roleVo);
                    continue;
                } else if (roleVo.getName().contains(searchString)) {
                    searchRoles.add(roleVo);
                    continue;
                }
            }
            redrawRoleVos(searchRoles);
        }
    }

    private void searchOrg() {
        List<OrgVo> orgVos = StudioApp.execute(new GetOrgsCmd());
        String searchString = searchOrgTextbox.getValue().trim();
        //点击全部，搜索内容为空
        List<OrgVo> searchRoles = new ArrayList<>();
        if (Strings.isBlank(searchString)) {
            searchRoles.addAll(orgVos);
        } else {
            for (OrgVo orgVo : orgVos) {
                if (orgVo.getId().contains(searchString)) {
                    searchRoles.add(orgVo);
                    continue;
                } else if (orgVo.getName().contains(searchString)) {
                    searchRoles.add(orgVo);
                    continue;
                }
            }
        }
        redrawOrgVos(searchRoles);
    }
}
